package com.test.current;

import com.test.until.UnSafeInstance;
import sun.misc.Unsafe;

import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.locks.LockSupport;

public class CustomizeAqsLock {

    /**
     * 加锁状态，使用cas机制保证
     */
    private volatile int state = 0;
    /**
     * 当前持有锁的线程
     */
    private Thread lockHolder;

    private static final Unsafe unsafe = UnSafeInstance.reflectGetUnsafe();
    /**
     * 变量在对象存储结构的偏移量
     */
    private static long sateOffset;
    static {
        try {
            sateOffset = unsafe.objectFieldOffset(CustomizeAqsLock.class.getDeclaredField("state"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 保存线程的使用情况   队列  FIFO  失败的线程去排队，逐个唤醒 队列必须是线程安全的
     *
     * LinkedBlockingQueue 已经是基于aqs实现的线程安全，不符合我们手写的初衷
     *
     * ConcurrentLinkedQueue  基于cas保证入队和出队的安全
     */
    ConcurrentLinkedQueue<Thread> waiters = new ConcurrentLinkedQueue<>();
    /**
     *
     * @param expect
     * @param update
     * @return
     */

    public final boolean compareAndSwapState(int expect,int update){
        return unsafe.compareAndSwapInt(this,sateOffset,expect,update);
    }

    public int getState() {
        return state;
    }

    public void setState(int state) {
        this.state = state;
    }

    public Thread getLockHolder() {
        return lockHolder;
    }

    public void setLockHolder(Thread lockHolder) {
        this.lockHolder = lockHolder;
    }
    public boolean acquire(){
        Thread currentThread = Thread.currentThread();
        //初始状态
        int c = getState();
        if (c == 0 ){
            //当前没有线程持有锁，且等待队列没有线程时或者是队列的头部元素时，才可以获取锁  实现公平锁，不允许插队
            if( (waiters.isEmpty()  || currentThread==waiters.peek()) &&compareAndSwapState(0,1)){
                setLockHolder(currentThread);
                return true;
            }
        }
        return false;
    }
    /**
     * 加锁
     */
    public void lock(){
        //尝试加锁
        if (acquire()){
            return;
        }
        Thread currentThread = Thread.currentThread();
        //加锁失败的进入等待
        waiters.add(currentThread);
        //加锁失败，必须停留在此，不能往下走  自旋（不能使用递归，影响内存，导致栈溢出（1m））
        for(;;){
            //对于没有抢到锁的线程 使其让其cpu 等待其他线程执行完毕后，按照先后顺序再次尝试加锁
            //Thread.yield();//  可以让当前正在执行的线程暂停，但它不会阻塞该线程，只是将该线程转入就绪状态。
            // yeild()只是让当前线程暂停一下，让系统的线程调度器重新调度一次，完全可能的情况是：当某个线程调用了yield()线程暂停之后，
            // 线程调度器又将其调度出来重新执行。依然占用cpu 不使用
//            try {
//                Thread.sleep(1000);  线程执行sleep()方法后会转入阻塞状态 但是睡眠时间与抢锁时机不可控
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }

            //使用unsafe 中park 和unpark  可以阻塞和唤醒线程  LockSupport提供了前面2个方法的包装
            //循环过程中，让队列中第一个等待线程去尝试获取
            if ((currentThread == waiters.peek()) && acquire()){
                //如果加锁成功，从队列中移除首部元素
                waiters.poll();
                //跳出死循环
                return;
            }
            //阻塞当前线程,释放cpu使用权  线程数据刷回内存的RSS-运行时状态段
            LockSupport.park(currentThread); //保存线程的使用情况   队列  FIFO  失败的线程去排队，逐个唤醒 队列必须是线程安全的

        }



    }

    /**
     * 解锁
     */
    public void unlock(){
        //判断当前线程是否锁的持有者
        if (Thread.currentThread() != lockHolder){
            throw new RuntimeException("lockHolder is not current Tread");
        }
        int state = getState();
        if (compareAndSwapState(state,0)){
            setLockHolder(null);
            //唤醒队列中排队的线程
            Thread first = waiters.peek();
            if (first != null){
                // park unpark 可以点对点唤醒/阻塞
                LockSupport.unpark(first);
            }
        }
    }
}
